{% if let Some(doc) = fn.documentation -%}
{{ crate::utils::prefix_lines(doc, "/// ") }}
{%- endif %}
func {{ fn.name }}(ctx context.Context{% for (name, go_type) in fn.args -%}
        , {{name}} {{go_type.serialize_type(pkg)}}
        {%- endfor %}, opts ...CallOptionFunc) ({{ fn.return_type.serialize_type(pkg) }}, error) {

    var callOpts callOption
    for _, opt := range opts {
        opt(&callOpts)
    }

    args := baml.BamlFunctionArguments{
        Kwargs: map[string]any{ {% for (name, go_type) in fn.args -%}"{{name}}": {{name}},{% endfor %} },
        Env: getEnvVars(callOpts.env),
    }

    if callOpts.clientRegistry != nil {
        args.ClientRegistry = callOpts.clientRegistry
    }

    if callOpts.collectors != nil {
        args.Collectors = callOpts.collectors
    }

    if callOpts.typeBuilder != nil {
        args.TypeBuilder = callOpts.typeBuilder
    }

    if callOpts.tags != nil {
        args.Tags = callOpts.tags
    }

    encoded, err := args.Encode()
    if err != nil {
        panic(err)
    }

    if callOpts.onTick == nil {
        result, err := bamlRuntime.CallFunction(ctx, "{{ fn.name }}", encoded, callOpts.onTick)
        if err != nil {
            return {{ fn.return_type.zero_value(pkg) }}, err
        }

        if result.Error != nil {
            return {{ fn.return_type.zero_value(pkg) }}, result.Error
        }

        casted := {{ fn.return_type.cast_from_function("result.Data", pkg) }}

        return casted, nil
    } else {
        channel, err := bamlRuntime.CallFunctionStream(ctx, "{{ fn.name }}", encoded, callOpts.onTick)
        if err != nil {
            return {{ fn.return_type.zero_value(pkg) }}, err
        }

        for result := range channel {
            if result.Error != nil {
                return {{ fn.return_type.zero_value(pkg) }}, result.Error
            }

            if result.HasData {
                return result.Data.({{ fn.return_type.serialize_type(pkg) }}), nil
            }
        }

        return {{ fn.return_type.zero_value(pkg) }}, fmt.Errorf("No data returned from stream")
    }
}